home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Shareware Overload Trio 2
/
Shareware Overload Trio Volume 2 (Chestnut CD-ROM).ISO
/
dir24
/
jnos110g.zip
/
BMUTIL.C
< prev
next >
Wrap
C/C++ Source or Header
|
1994-08-26
|
43KB
|
1,527 lines
/*
* Simple mail user interface for KA9Q IP/TCP package.
* A.D. Barksdale Garbee II, aka Bdale, N3EUA
* Copyright 1986 Bdale Garbee, All Rights Reserved.
* Permission granted for non-commercial copying and use, provided
* this notice is retained.
* Copyright 1987 1988 Dave Trulli NN2Z, All Rights Reserved.
* Permission granted for non-commercial copying and use, provided
* this notice is retained.
*
* Ported to NOS at 900120 by Anders Klemets SM0RGV.
*
* Userlogging, 'RM' and 'KM' implementation,
* more-prompts for all types
* 920307 and later, by Johan. K. Reinalda, WG7J/PA3DIS
* Mail indexing by Johan. K. Reinalda, WG7J, June/July 1993
*/
#ifdef MSDOS
#include <io.h>
#endif
#include <fcntl.h>
#include <sys\stat.h>
#include <ctype.h>
#include <time.h>
#include <conio.h>
#ifdef MSDOS
#include <dir.h>
#include <dos.h>
#endif
#include "global.h"
#include "ftpserv.h"
#include "smtp.h"
#include "proc.h"
#include "usock.h"
#include "socket.h"
#include "telnet.h"
#include "timer.h"
#include "session.h"
#include "files.h"
#include "mailbox.h"
#include "cmdparse.h"
#include "bm.h"
#include "mailutil.h"
#include "dirutil.h"
#include "index.h"
#define SETVBUF
#if defined(UNIX) || defined(MICROSOFT)
#include <sys/types.h>
#endif
/*
#if defined(UNIX) || defined(MICROSOFT) || defined(__TURBOC__)
#include <sys/stat.h>
#endif
#ifdef AZTEC
#include <stat.h>
#endif
*/
#include <fcntl.h>
#include "bm.h"
#include "mailbox.h"
#ifdef SETVBUF
#define MYBUF 1024
#endif
#ifdef MAILCMDS
char Badmsg[] = "Invalid Message number %d\n";
char Nomail[] = "No messages\n";
static char Noaccess[] = "Unable to access %s\n";
static char OpenError[] = "user %s: error %d opening %s\n";
static int readnotes __ARGS((struct mbx *m,int ifile));
static long isnewmail __ARGS((struct mbx *m));
static int initnotes __ARGS((struct mbx *m));
static int lockit __ARGS((struct mbx *m));
static int unlockit __ARGS((struct mbx *m));
static int
initnotes(m)
struct mbx *m;
{
int idx;
char *area;
int ret;
char buf[FILE_PATH_SIZE];
/* Reset all mailbox status variables */
m->change = m->anyread = m->nmsgs = m->current = m->newmsgs = 0;
m->mboxsize = 0L;
area = strdup(m->area);
dirformat(area);
sprintf(buf,"%s/%s.ind",Mailspool,area);
free(area);
if ((idx = open(buf,READBINARY)) == -1)
/* No mail ! */
return 0;
ret = readnotes(m,idx);
close(idx);
if (ret != 0)
return -1;
return 0;
}
/* readnotes assumes that idx is pointing to the index file */
static int
readnotes(m,idx)
struct mbx *m;
int idx;
{
char buf[LINELEN];
struct let *oldmbox;
int len,i;
long pos;
char status;
struct let *cmsg;
struct indexhdr hdr;
struct mailindex ind;
/* Get the number of messages in the mailbox */
lseek(idx,0L,SEEK_SET);
if (read_header(idx,&hdr) == -1) return -1;
if(m->mbox)
oldmbox = m->mbox;
else
oldmbox = NULL;
/* Get the new number of messages */
m->mbox = (struct let *)callocw(hdr.msgs+1,sizeof(struct let));
if(oldmbox) { /* Copy the status of the messages back */
if (m->nmsgs <= hdr.msgs) /* unless mbox shrank */
memcpy(m->mbox,oldmbox,(m->nmsgs+1)*sizeof(struct let));
else m->current=0;
free(oldmbox);
}
else m->current=0;
cmsg = m->mbox;
pos = 0;
m->nmsgs = 0;
m->newmsgs = 0;
memset(&ind,0,sizeof(ind));
default_index(m->area,&ind);
/* Check for unread(ie. new) messages */
for(i=1;i<=hdr.msgs;i++) {
pwait(NULL);
cmsg++;
m->nmsgs++;
if (read_index(idx,&ind) == -1) { /* should never happen */
m->nmsgs--;
log(-1,"readnotes: index for %s is damaged (#%d)", m->area, i);
break;
}
#ifdef USERLOG
cmsg->msgid = ind.msgid;
#endif
cmsg->size = ind.size;
cmsg->start = pos;
pos += cmsg->size;
cmsg->status |= ind.status;
#ifdef USERLOG
if(m->areatype == AREA)
if(cmsg->msgid <= m->lastread)
cmsg->status |= BM_READ;
#endif
if(!(cmsg->status & BM_READ)) {
m->newmsgs++;
if(m->current == 0)
m->current = m->nmsgs; /* first new message */
}
default_index(m->area,&ind);
}
/* start at one if no new messages */
if(m->current == 0)
m->current++;
m->mboxsize = pos;
#ifdef JPDEBUG
if (pos < 0L || pos > 4000000L)
log(-1,"readnotes: suspicious len %ld for %s", pos, m->area);
#endif
if(m->areatype == PRIVATE) /* our private mail area */
m->mycnt = m->nmsgs;
if (m->nmsgs == hdr.msgs) return 0;
else return -1;
}
static char ListHeader[] = "St. # TO FROM DATE SIZE SUBJECT\n";
/* list headers of a notesfile a message */
/* Rearranged display - WG7J */
int
dolistnotes(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct mbx *m;
struct let *cmsg;
char *cp, *s, *datestr;
int idx;
char *area;
char type;
char status;
int start, stop;
long pos;
int i,len,header,list,listed;
#ifdef USERLOG
long msgid;
#endif
long size;
int c,usemore=0,lin;
struct indexhdr hdr;
struct mailindex ind;
char buf[FILE_PATH_SIZE];
m = (struct mbx *) p;
/* If this user doesn't have read-permissions,
* we're not going to let him list anything - WG7J
*/
if(m->privs & NO_READCMD) {
tputs(Noperm);
return 0;
}
if(m->nmsgs == 0) {
tputs(Nomail);
return 0;
}
if((m->stype == '>' || m->stype == '<' || m->stype == 'S') && argc == 1) {
tputs("Search criterium needed!\n");
return 0;
}
if((lin=m->morerows) != 0)
usemore = 1; /* Display More prompt */
area = strdup(m->area);
dirformat(area);
sprintf(buf,"%s/%s.ind",Mailspool,area);
free(area);
if((idx = open(buf,READBINARY)) == -1) {
closenotes(m);
tprintf("Can not read index file %s\n",buf);
return 0;
}
tprintf("Mail area: %s\n"
"%d message%s - %d new\n\n",
m->area,m->nmsgs,m->nmsgs == 1 ? " " : "s ", m->newmsgs);
stop = m->nmsgs;
#ifdef USERLOG
if(m->areatype != PRIVATE && m->stype != 'A')
start = stop - m->newmsgs + 1;
else
#endif
if((argc == 1) & (m->stype == 'L'))
start = stop;
else
start = 1;
if(argc > 1) {
if(m->stype == 'L') /* LL (List Last) command */
start = stop - atoi(argv[1]) + 1;
else
start = atoi(argv[1]);
if(argc > 2)
stop = atoi(argv[2]);
/* Check the boundaries */
if(stop > m->nmsgs)
stop = m->nmsgs;
if(start < 1)
start = 1;
}
if(start > stop) {
if((m->stype == ' ') || (m->stype == 'M'))
tputs("None to list.\n");
else
tputs("Invalid range.\n");
close(idx);
return 0;
}
cmsg = m->mbox;
header = 0;
listed = 0;
memset(&ind,0,sizeof(ind));
default_index(m->area,&ind);
/* Read the index file header */
if (read_header(idx,&hdr) == 0)
for(i=1;i<=hdr.msgs;i++) {
pwait(NULL);
if (read_index(idx,&ind) == -1) goto irerr;
cmsg++;
if(start <= i && i <= stop) {
list = 1;
/* Now see if we should list this one */
if(m->stype == ' ') {
if(argc > 1)
list = 1;
else if(cmsg->status & BM_READ)
list = 0;
} else if(m->stype == '>') {
if(strstr(ind.to,argv[1]) == NULL)
list = 0;
} else if( m->stype == '<' ||
(m->stype == 'M' && m->areatype != PRIVATE)) {
if(strstr(ind.from,argv[1]) == NULL)
list = 0;
} else if(m->stype == 'S') {
cp = strlwr(strdup(ind.subject)); /* case-independent scan */
if(strstr(cp,argv[1]) == NULL)
list = 0;
free(cp);
} else if(m->stype == 'B' || m->stype == 'T')
if(m->stype != ind.type)
list = 0;
if(list) {
#ifdef USERLOG
/* Check the ID number of this message and
* adjust new lastread count, if needed - WG7J
*/
if(cmsg->msgid > m->lastread)
m->newlastread = cmsg->msgid;
#endif
if(!header) {
tputs(ListHeader);
lin--;
header = 1;
}
listed = 1;
/* Format date */
datestr = ctime(&ind.date);
datestr[10] = '\0';
/* Format from */
if((cp = strchr(ind.from,'@')) != NULL)
*cp = '\0';
if((cp = strchr(ind.from,'%')) != NULL)
*cp = '\0';
tputc((i == m->current) ? '>' : ' ');
tputc(cmsg->status & BM_DELETE ? 'D' : ' ');
tputc(cmsg->status & BM_HOLD ? 'H':(cmsg->status & BM_READ ? 'Y' : 'N'));
tprintf(" %3d %-13.13s %-8.8s %-6.6s %4ld %-35.35s\n",
i,ind.to,ind.from,&datestr[4],ind.size,ind.subject);
lin--;
/* More prompting added - WG7J */
if(usemore && lin <= 0){
if(charmode_ok(m))
c = tkeywait(TelnetMorePrompt,0);
else /* For AX.25 and NET/ROM connects - WG7J */
c = mykeywait(BbsMorePrompt,m);
if(c == -1 || c == 'q' || c == 'Q')
break;
if(c == '\n' || c == '\r')
lin = 1;
else
lin = m->morerows-1;
header = 0;
}
}
}
/* Done with this index, clear it */
default_index(m->area,&ind);
}
else
irerr:
tprintf("Error reading index of %s\n", m->area);
close(idx);
if(!listed)
tputs(Nomail);
return 0;
}
/* save msg on stream - if noheader set don't output the header */
int
msgtofile(m)
struct mbx *m;
{
FILE *fp;
char *area;
char buf[LINELEN];
if (m->nmsgs == 0) {
tputs(Nomail);
return -1;
}
/* Open the mailbox and go to start of message */
area = strdup(m->area);
dirformat(area);
sprintf(buf,"%s/%s.txt",Mailspool,area);
if ((fp=fopen(buf,READ_TEXT)) == NULLFILE) {
free(area);
return -1;
}
free(area);
fseek(fp,m->mbox[m->current].start,0);
/* skip header */
while(fgets(buf,sizeof(buf),fp) != NULLCHAR)
if (*buf == '\n')
break;
/* Copy the body */
while (fgets(buf,sizeof(buf),fp) != NULLCHAR) {
if(!strncmp(buf,"From ",5))
break;
fputs(buf,m->tfile);
if (ferror(m->tfile)) {
tputs("Error writing mail file\n");
fclose(fp);
return -1;
}
}
fclose(fp);
return 0;
}
/* dodelmsg - delete message in current notesfile */
/* Modified to allow the 'KM' command. 920307 - WG7J */
int
dodelmsg(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct mbx *m;
int msg,i;
char *myargv[NARG];
int myargc;
int maxmsg;
struct let *cmsg;
char *tmpbuf;
int start;
int end;
m = (struct mbx *) p;
if (m->nmsgs == 0) {
tputs(Nomail);
return 0;
}
/* If this user doesn't have read-permissions,
* we're not going to let him kill anything;
* allow anyone to kill messages in areas
* who's names start with 'nts' - WG7J
*/
/* Check if we have permission to delete others mail */
if( (m->privs & NO_SENDCMD) ||
(m->privs & NO_READCMD) ||
( !(m->privs & FTP_WRITE) &&
!(m->areatype == PRIVATE) &&
strnicmp(m->area,"nts",3)) ){
tputs(Noperm);
return 0;
}
/* If this is KA, Kill All messages */
if(m->stype == 'A') {
if(m->nmsgs) {
for(i=1,cmsg=&m->mbox[1];i<=m->nmsgs;i++,cmsg++)
cmsg->status |= BM_DELETE;
m->change = 1;
tprintf("%d message%s killed!\n",m->nmsgs,(m->nmsgs==1) ? "" : "s");
}
return 0;
}
/* If this is the KM command, setup myargv[]
* to contain up to NARG message numbers - WG7J
*/
if(m->stype == 'M') {
/* scan all messsages to find unread ones */
cmsg = &m->mbox[1];
myargc = 1;
i = 0;
while(myargc < NARG && i < m->nmsgs) {
if(cmsg->status & BM_READ) { /*found a read msg!*/
tmpbuf = mallocw(17); /*allocate space for the new argument*/
myargv[myargc++] = itoa(i+1,tmpbuf,10);
}
i++;
cmsg++;
}
if(myargc == 1) {
tputs("Nothing to kill\n");
return 0;
}
argc = myargc;
} else {
if(argc == 1) {
msg = m->current;
if(m->stype == 'U')
m->mbox[msg].status &= ~BM_DELETE;
else {
m->mbox[msg].status |= BM_DELETE;
m->change = 1;
}
tprintf("Msg %d %sKilled.\n", msg,(m->stype=='U') ? "Un-" : "");
return 0;
}
/*simply point to the old arguments*/
for(i=1;i<argc;i++)
myargv[i] = argv[i];
}
/* See if x - y format was used and use a for i = x to y loop */
if(myargv[2][0] == '-') {
start = atoi(myargv[1]);
end = atoi(myargv[3]);
if(start < 0 || start > m->nmsgs || end < 0 || end > m->nmsgs ) {
tprintf(Badmsg,start);
start = end+1;
}
for(i=start;i<=end;i++) {
msg = i;
if(m->stype == 'U')
m->mbox[msg].status &= ~BM_DELETE;
else {
m->mbox[msg].status |= BM_DELETE;
m->change = 1;
}
tprintf("Msg %d %sKilled.\n", msg,(m->stype=='U') ? "Un-" : "");
} /* endfor */
} else for(i = 1; i < argc; ++i) {
tmpbuf = strchr(myargv[i],'-'); /* N5KNX: allow from-to msg specification */
msg = atoi(myargv[i]);
if (tmpbuf == NULLCHAR)
maxmsg = msg;
else
maxmsg = atoi(++tmpbuf);
if (maxmsg < msg) {
tprintf(Badmsg,maxmsg);
continue;
}
for (; msg <= maxmsg; msg++) {
if(msg < 0 || msg > m->nmsgs) {
tprintf(Badmsg,msg);
continue;
}
if(m->stype == 'U')
m->mbox[msg].status &= ~BM_DELETE;
else {
m->mbox[msg].status |= BM_DELETE;
m->change = 1;
}
tprintf("Msg %d %sKilled.\n", msg,(m->stype=='U') ? "Un-" : "");
}
}
/* If this was 'KM'
* free the memory allocated for myargv[] - WG7J
*/
if(m->stype == 'M') {
for(i=1;i<argc;i++)
free(myargv[i]);
}
return 0;
}
void no_area(struct mbx *m) {
m->area[0] = '\0';
m->nmsgs = m->current = m->newmsgs = 0;
m->mboxsize = 0;
free(m->mbox);
m->mbox = NULL;
}
/* close the temp file while copying mail back to the mailbox */
int
closenotes(m)
struct mbx *m;
{
struct let *cmsg;
char *area;
int i,msgs,keep,error;
long start,pos,size;
int idx,idxnew;
FILE *txt,*new;
char len[10],lens[7];
char buf[LINELEN];
char old[LINELEN];
struct fwdbbs *newbbs;
struct indexhdr hdr;
struct mailindex ind;
if(m->nmsgs == 0)
return 0;
if(lockit(m))
return -1;
if(!m->change || (isnewmail(m) < 0L)) {
/* no changes were made,
* or some messages were deleted !
* In the latter we cannot continue !
*/
#ifdef DEBUG_HDR
if (m->change) log(m->user,"NOUPDATE for %s: msgs deleted in %s",m->name,m->area);
#endif
unlockit(m);
no_area(m);
return 0;
}
scanmail(m);
area = strdup(m->area);
dirformat(area);
sprintf(buf,"%s/%s.txt",Mailspool,area);
if((txt = fopen(buf,READ_BINARY)) == NULLFILE) {
free(area);
log(m->user,OpenError,m->name,errno,buf);
unlockit(m);
no_area(m);
return -1;
}
sprintf(buf,"%s/%s.ind",Mailspool,area);
if((idx = open(buf,READBINARY)) == -1) {
free(area);
fclose(txt);
log(m->user,OpenError,m->name,errno,buf);
unlockit(m);
no_area(m);
return -1;
}
sprintf(buf,"%s/%s.new",Mailspool,area);
if((new = fopen(buf,WRITE_TEXT)) == NULLFILE) {
free(area);
fclose(txt);
close(idx);
log(m->user,OpenError,m->name,errno,buf);
unlockit(m);
no_area(m);
return -1;
}
sprintf(buf,"%s/%s.idn",Mailspool,area);
if((idxnew = open(buf,CREATEBINARY,CREATEMODE)) == -1) {
free(area);
fclose(txt);
close(idx);
fclose(new);
log(m->user,OpenError,m->name,errno,buf);
unlockit(m);
no_area(m);
return -1;
}
msgs = error = 0;
memset(&ind,0,sizeof(ind));
default_index(m->area,&ind);
if (read_header(idx,&hdr) == -1) {
error++;
#ifdef DEBUG_HDR
log(-1,"read_header err %d for %s", errno, m->area);
#endif
goto cleanup;
}
/* write the header first to new index file */
default_header(&hdr);
if (write_header(idxnew,&hdr) == -1) {
error++;
#ifdef DEBUG_HDR
log(-1,"write_header err %d for %s", errno, m->area);
#endif
goto cleanup;
}
/* Copy messages and delete msgs, add status or fwd headers */
for(cmsg=&m->mbox[1],i = 1; i <= m->nmsgs; i++, cmsg++) {
default_index("",&ind); /* Free memory from previous index */
/* Read the index for this message */
if(read_index(idx,&ind) == -1) {
puts("\n\007\007 Warning: Index files not in sync ! Run MAIL2IND asap!!\n");
#ifdef MAILERROR
mail_error("Warning: Index files not in sync ! Run MAIL2IND asap!!\n");
#endif
#ifdef DEBUG_HDR
log(m->user,"NOUPDATE for %s: %s.ind out-of-sync",m->name,m->area);
#endif
free(area);
close(idx);
fclose(txt);
fclose(new);
close(idxnew);
unlockit(m);
no_area(m);
return -1;
}
keep = 0;
if(!(cmsg->status & BM_DELETE)) {
/* Keep this message ! */
keep = 1;
msgs++;
start = ftell(new);
fseek(txt,cmsg->start,0);
/* Copy this one to the new file,
* start with the smtp header
* The received: line is first
*/
while(bgets(buf,sizeof(buf),txt) != NULL) {
pwait(NULL);
if(*buf == '\0') {
/* End of headers */
if(cmsg->status & BM_FORWARDED) {
fprintf(new,"%s%s\n",Hdrs[XFORWARD],m->name);
newbbs = mallocw(sizeof(struct fwdbbs));
strcpy(newbbs->call,m->name);
newbbs->next = ind.bbslist;
ind.bbslist = newbbs;
}
if(!(ind.status & BM_READ) && (cmsg->status & BM_READ) &&
(m->areatype == PRIVATE)) {
fprintf(new,"%sR\n",Hdrs[STATUS]);
ind.status |= BM_READ;
}
fputc('\n',new);
break;
}
fprintf(new,"%s\n",buf);
}
/* Now do the message body */
pos = ftell(new);
while(bgets(buf,sizeof(buf),txt) != NULL) {
pwait(NULL);
if(!strncmp(buf,"From ",5)) {
/* End of message, write index */
ind.size = pos-start;
if (WriteIndex(idxnew,&ind)) error++;
keep=0; /* should be redundant, but... */
break;
}
fprintf(new,"%s\n",buf);
pos = ftell(new);
}
} /* If not message deleted */
} /* for all messages */
/* do we need to keep the last one ? */
if(keep) {
/* End of message, rewrite index line */
ind.size = pos-start;
if (WriteIndex(idxnew,&ind)) error++;
}
/* Free the last index */
default_index("",&ind);
size = ftell(new);
/* If we have no errors, then delete the old mail and index files,
* and rename the new one.
*/
if(ferror(new)) error++;
cleanup:
fclose(txt);
close(idx);
fclose(new);
close(idxnew);
if(!error) {
sprintf(buf,"%s/%s.txt",Mailspool,area);
sprintf(old,"%s/%s.new",Mailspool,area);
unlink(buf);
if(size)
rename(old,buf);
else
/* remove a zero length file */
unlink(old);
sprintf(buf,"%s/%s.ind",Mailspool,area);
sprintf(old,"%s/%s.idn",Mailspool,area);
unlink(buf);
if(size)
rename(old,buf);
else {
/* remove a zero length file */
unlink(old);
#ifdef USERLOG
sprintf(buf,"%s/%s.inf",Mailspool,area);
unlink(buf);
#endif
}
}
#ifdef DEBUG_HDR
else
log(m->user,"NOUPDATE for %s: error writing new %s.txt",m->name,m->area);
#endif
unlockit(m);
no_area(m);
free(area);
if(m->areatype == PRIVATE)
m->mycnt = msgs; /* Update the size of our private mailbox */
return (error ? -1 : 0);
}
static int
unlockit(m)
struct mbx *m;
{
if(--m->lockcnt) return(0);
return(rmlock(Mailspool, m->area));
}
static int
lockit(m)
struct mbx *m;
{
int c, cnt = 0;
char *area;
char MailFileBusy[] = "Mail file is busy. Retry? (y/n)";
if(m->lockcnt++) return(0); /* already locked, just incr cntr */
area = strdup(m->area);
dirformat(area);
while(mlock(Mailspool,area)) {
pause(1000L); /* Wait one second */
if(++cnt == 10) {
cnt = 0;
switch (m->state) {
case MBX_REVFWD:
case MBX_FORWARD:
#ifdef DEBUG_HDR
log(m->user,"NOUPDATE for %s: can't lock %s",m->name,m->area);
#endif
case MBX_TRYING:
c='n';
break;
default:
if(charmode_ok(m))
c = tkeywait(MailFileBusy,1);
else /* For AX.25 and NET/ROM connects - WG7J */
c = mykeywait(MailFileBusy,m);
break;
}
if (c == -1 || c == 'n' || c == 'N') {
m->nmsgs = 0;
m->mboxsize = 0;
free(area);
m->lockcnt = 0;
return 1;
}
}
}
free(area);
return 0;
}
/* read the next message or the current one if new */
int
doreadnext(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct mbx *m;
char buf[10], *newargv[2];
m = (struct mbx *) p;
if(m->nmsgs == 0) /* No mail ! */
return 0;
if((m->mbox[m->current].status & BM_READ) != 0) {
if (m->current == 1 && m->anyread == 0)
;
else if (m->current < m->nmsgs) {
m->current++;
} else {
tputs("Last message\n");
return 0;
}
}
sprintf(buf,"%d",m->current);
newargv[0] = "r";
newargv[1] = buf;
m->anyread = 1;
return doreadmsg(2,newargv,p);
}
extern int MbRead;
/* display message on the crt given msg number */
/* Modified to allow the 'RM' command, 920307 - WG7J */
int
doreadmsg(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct mbx *m;
int c, col, lin;
char *area, *cp, *cp2;
int msg, cnt, i, usemore=0, verbose;
int smtpheader, mbxheader, pathheader, print;
FILE *txt;
char *myargv[NARG];
int myargc;
int maxmsg;
struct let *cmsg;
char *tmpbuf;
char buf[LINELEN];
m = (struct mbx *) p;
/*Check for read-permissions - WG7J */
if(m->privs & NO_READCMD) {
tputs(Noperm);
return 0;
}
if (m->nmsgs == 0) {
tputs(Nomail);
return 0;
}
if((lin=m->morerows) != 0)
usemore = 1; /* Display More prompt */
/*If this is the RM or VM command, setup myargv[]
*to contain up to NARG message numbers - WG7J
*/
if(m->stype == 'M') {
if(!m->newmsgs) {
tputs(Nomail);
return 0;
}
/* scan all messsages to find unread ones */
cmsg = &m->mbox[1];
myargc = 1;
i = 0;
while(myargc < NARG && i < m->nmsgs) {
if(!(cmsg->status & BM_READ)) { /*found an unread msg!*/
tmpbuf = mallocw(17); /*allocate space for the new argument*/
myargv[myargc++] = itoa(i+1,tmpbuf,10);
}
i++;
cmsg++;
}
argc = myargc;
} else {
/*simply point to the old arguments*/
for(i=1;i<argc;i++)
myargv[i] = argv[i];
}
if(argc == 1) {
tputs("Usage: Read/Verbose #\n");
return 0;
}
m->state = MBX_READ;
/* Open the text file */
area = strdup(m->area);
dirformat(area);
sprintf(buf,"%s/%s.txt",Mailspool,area);
free(area);
if((txt=fopen(buf,READ_TEXT)) == NULLFILE) {
tprintf("Cannot open mail file %s\n",area);
return 0;
}
if((*argv[0] == 'v') || (m->stype == 'H'))
verbose = 1; /* display all header lines */
else
verbose = 0;
for(i = 1; i < argc; ++i) {
tmpbuf = strchr(myargv[i],'-'); /* N5KNX: allow from-to msg specification */
msg = atoi(myargv[i]);
if (tmpbuf == NULLCHAR)
maxmsg = msg;
else
maxmsg = atoi(++tmpbuf);
if (maxmsg < msg) {
tprintf(Badmsg,maxmsg);
continue;
}
for (; msg <= maxmsg; msg++) {
if(msg < 1 || msg > m->nmsgs) {
tprintf(Badmsg,msg);
goto iamdone;
}
cmsg = &m->mbox[msg];
/* if the message is on hold, only show to sysops - WG7J */
if((cmsg->status & BM_HOLD) && !(m->privs & SYSOP_CMD)) {
tprintf("Msg %d:",msg);
tputs(Noperm);
continue;
}
MbRead++;
#ifdef USERLOG
/* Check the ID number of this message and
* adjust new lastread count, if needed - WG7J
*/
if(cmsg->msgid > m->lastread)
m->newlastread = cmsg->msgid;
#endif
m->current = msg;
/* Only mark your own private area as read and changed.
* other areas, only mark as read, NOT changed !
* 910312 - WG7J
*/
if(!(cmsg->status & BM_READ)) {
cmsg->status |= BM_READ;
m->newmsgs--;
if(m->areatype == PRIVATE)
m->change = 1;
}
tprintf("Message #%d %s\n", msg,
cmsg->status & BM_DELETE ? "[Deleted]" : "");
--lin;
fseek(txt,cmsg->start,0);
fgets(buf,sizeof(buf),txt); /* the 'From ' line */
if(verbose) {
tputs(buf);
lin--;
}
smtpheader = 1;
while(fgets(buf,sizeof(buf),txt) != NULL) {
if(!strncmp(buf,"From ",5))
break;
print = 1;
if(!verbose) {
if(smtpheader) {
if(*buf == '\n') {
smtpheader = 0;
mbxheader = 1;
pathheader = 0;
} else {
switch(htype(buf)) {
case TO:
case CC:
case FROM:
case DATE:
case SUBJECT:
case REPLYTO:
case APPARTO:
break;
default:
print = 0;
}
}
} else if(mbxheader) {
if(*buf == '\n') {
mbxheader = 0;
}
print = 0;
if(strncmp(buf,"R:",2) || \
((cp=strchr(buf,'@')) == NULL) ) {
print = 1;
mbxheader = 0;
if(pathheader)
tputc('\n');
} else {
if(pathheader > 7)
continue;
if(*++cp == ':')
cp++;
cp2 = cp;
while(*cp2 != '.' && *cp2 != ' ' && *cp2 != '\n')
cp2++;
*cp2 = 0;
if(++pathheader == 1) {
tputs(Hdrs[PATH]);
tputs(cp);
} else {
pathheader++;
tputc('!');
tputs(cp);
}
}
}
}
if(print) {
tputs(buf);
if(usemore && --lin <= 0){
if(charmode_ok(m))
c = tkeywait(TelnetMorePrompt,0);
else /* For AX.25 and NET/ROM connects - WG7J */
c = mykeywait(BbsMorePrompt,m);
lin = m->morerows;
if(c == -1 || c == 'q' || c == 'Q')
break;
if(c == '\n' || c == '\r')
lin = 1;
}
}
}
}
}
iamdone:
fclose(txt);
/* If this was 'RM' or 'VM',
* free the memory allocated for myargv[] - WG7J
*/
if(m->stype == 'M') {
for(i=1;i<argc;i++)
free(myargv[i]);
}
return 0;
}
/* Set up m->to when replying to a message. The subject is returned in
* m->line.
*/
int
mbx_reply(argc,argv,m,cclist,rhdr)
int argc;
char *argv[];
struct mbx *m;
struct list **cclist; /* Pointer to buffer for pointers to cc recipients */
char **rhdr; /* Pointer to buffer for extra reply headers */
{
char *cp;
int msg;
struct cclist *cc;
struct mailindex ind;
if(argc == 1)
msg = m->current;
else
msg = atoi(argv[1]);
if(msg < 1 || msg > m->nmsgs) {
if(m->sid & MBX_SID)
tputs("NO - ");
tprintf(Badmsg,msg);
return -1;
}
/* clear index */
memset(&ind,0,sizeof(struct mailindex));
/* Get the index for this message */
cp = strdup(m->area);
dirformat(cp);
if(get_index(msg,cp,&ind) == -1) {
free(cp);
return -1;
}
free(cp);
/* Free anything that might be allocated
* since the last call to mbx_to() or mbx_reply()
*/
free(m->to);
m->to = NULLCHAR;
free(m->tofrom);
m->tofrom = NULLCHAR;
free(m->tomsgid);
m->tomsgid = NULLCHAR;
free(m->origto);
m->origto = NULLCHAR;
/* Assign data from the index */
if(strlen(ind.replyto))
m->to = strdup(ind.replyto);
else
m->to = strdup(ind.from);
if(strncmp(ind.subject,"Re: ",4))
sprintf(m->line,"Re: %s",ind.subject);
else
strcpy(m->line,ind.subject);
for(cc=ind.cclist;cc;cc=cc->next)
addlist(cclist,cc->to,0);
*rhdr = mallocw(LINELEN);
sprintf(*rhdr,"In-Reply-To: your message of %s"
" <%s>\n",
ctime(&ind.date),ind.messageid);
/* Free the index */
default_index("",&ind);
return 0;
}
#ifdef USERLOG
/*get the last message listed/read
*from the areaname.USR file
*keeps track for each user.
*February '92, WG7J
*/
void
getlastread(m)
struct mbx *m;
{
FILE *Alog;
char buf[256];
char *cp;
int found=0;
m->lastread = m->newlastread = 0L;
sprintf(buf,"%s/%s.usr",Mailspool,m->area);
if ((Alog = fopen(buf,"r+")) == NULLFILE) {
/* USR file doesn't exist, create it */
if((Alog = fopen(buf,"w")) == NULLFILE)
return;
/* Add this user as first one */
sprintf(buf,"%s 0\n",m->name);
fputs(buf,Alog);
fclose(Alog);
return;
}
/*Find user in the usr file for this area*/
for(;;) {
if(fgets(buf,sizeof(buf),Alog) == NULLCHAR)
break;
if((cp=strchr(buf,' ')) != NULLCHAR)
*cp = '\0';
if(!stricmp(m->name,buf)) {
/*found user*/
cp++;
while(*cp == ' ') /*skip blanks*/
cp++;
m->lastread = atol(cp);
found = 1;
break;
}
}
if(!found) {
/*Add user*/
sprintf(buf,"%s 0\n",m->name);
fputs(buf,Alog);
}
fclose(Alog);
return;
}
/* Write the new last read id number to the USR file - WG7J
* only update if this is not a bbs,
* current area is a public area and not 'help',
* or anything that starts with 'sys',
* and a new message was actually listed/read
*/
void
setlastread(m)
struct mbx *m;
{
FILE *Alog, *tfile;
char *cp;
char buf[80];
char tmpname[80];
if((m->sid & MBX_SID) || (m->newlastread <= m->lastread) )
return;
/* Rename the USR file to a tempfile */
sprintf(buf,"%s/%s.usr",Mailspool,m->area);
/* N5KNX: change suffix from .usr to .tmp */
sprintf(tmpname,"%s/%s.tmp",Mailspool,m->area);
if(rename(buf,tmpname))
/* Can't rename ??? */
return;
if((Alog = fopen(buf,"w")) == NULLFILE) {
/* can't creat new USR file ???*/
rename(tmpname,buf); /* try to undo the damage */
return;
}
if((tfile = fopen(tmpname,"r")) == NULLFILE)
/* can't open renamed file ??? */
return;
/*Write all users back, but update this one!*/
while(fgets(buf,sizeof(buf),tfile) != NULLCHAR) {
if((cp=strchr(buf,' ')) != NULLCHAR)
*cp = '\0';
if(!stricmp(m->name,buf)) {
/*found this user*/
sprintf(buf,"%s %lu\n",m->name,m->newlastread);
} else
*cp = ' '; /* restore the space !*/
fputs(buf,Alog);
}
fclose(tfile);
unlink(tmpname);
fclose(Alog);
return;
}
#endif /*USERLOG*/
void
scanmail(m) /* Get any new mail */
struct mbx *m;
{
int idx;
char *area;
int ret;
char buf[FILE_PATH_SIZE];
long diff;
if(lockit(m))
return;
if ((diff = isnewmail(m)) == 0L) {
unlockit(m);
return;
}
if(diff < 0L) {
/* Area wasn't open yet, or the file size has decreased.
* Any changes we did to this area will be lost,
* but this is not fatal.
*/
#ifdef DEBUG_HDR
if (diff < -1L) log(m->user,"NOUPDATE for %s: msgs deleted in %s [scanmail] %ld,%ld,%d",m->name,m->area,diff,m->mboxsize,errno);
#endif
initnotes(m);
unlockit(m);
return;
}
area = strdup(m->area);
dirformat(area);
sprintf(buf,"%s/%s.ind",Mailspool,area);
if ((idx = open(buf,READBINARY)) == -1)
log(m->user,OpenError,m->name,errno,buf);
else {
/* Reread all messages since they may have changed
* in size after an X-Forwarded-To line was added.
*/
ret = readnotes(m,idx); /* get the mail */
close(idx);
if(m->areatype == PRIVATE)
m->mycnt = m->nmsgs;
if (ret != 0)
tputs("Error updating mail file\n");
}
unlockit(m);
free(area);
}
/* Check the current mailbox to see if new mail has arrived.
* Returns the difference in size.
*/
static long
isnewmail(m)
struct mbx *m;
{
int idx;
long size;
char *area;
char buf[FILE_PATH_SIZE];
if(lockit(m)) return(-1); /* SyncIndex assumes a lock */
SyncIndex(m->area); /* ensure index file is current */
unlockit(m);
area = strdup(m->area);
dirformat(area);
sprintf(buf,"%s/%s.ind",Mailspool,area);
free(area);
if((idx = open(buf,READBINARY)) == -1) {
if(m->mboxsize == 0)
return 0;
return -1;
}
close(idx);
/* index file exists, check mailbox */
strcpy(&buf[strlen(buf) - 3],"txt");
size = fsize(buf);
if(m->mboxsize == 0) {
if(size > 0)
return -1; /* New open of mailbox */
return 0; /* No mail; no change */
}
/* Others */
return size - m->mboxsize;
}
/* Check if the private mail area has changed */
long
isnewprivmail(m)
struct mbx *m;
{
int idx,msgcnt;
struct indexhdr hdr;
char buf[FILE_PATH_SIZE];
sprintf(buf,"%s/%s.ind",Mailspool,m->name);
if((idx=open(buf,READBINARY)) == -1)
hdr.msgs = 0;
else {
read_header(idx,&hdr);
close(idx);
}
return hdr.msgs - m->mycnt; /* != 0 not more than once */
}
#endif /* MAILCMDS */
/* This function returns the length of a file. The proper thing would be
* to use stat(), but it fails when using DesqView together with Turbo-C
* code.
*/
long
fsize(name)
char *name;
{
long cnt;
FILE *fp;
if((fp = fopen(name,READ_TEXT)) == NULLFILE)
return -1L;
fseek(fp,0L,2);
cnt = ftell(fp);
fclose(fp);
return cnt;
}
/* Print prompt and read one character, telnet version */
int
tkeywait(prompt,flush)
char *prompt; /* Optional prompt */
int flush; /* Flush queued input? */
{
int c, i, oldimode,oldomode;
if(flush && socklen(Curproc->input,0) != 0)
recv_mbuf(Curproc->input,NULL,0,NULLCHAR,0); /* flush */
if(prompt == NULLCHAR)
prompt = "Hit enter to continue";
usflush(Curproc->output); /* BSD-derived telnets need opts in separate pkt */
while (socklen(Curproc->output, 1) > 0) /* else CRs in pkt are ignored */
pause(250L);
tprintf("%s%c%c%c%c%c%c",prompt,IAC,WILL,TN_ECHO,IAC,WILL,TN_SUPPRESS_GA);
usflush(Curproc->output);
/* discard the response */
oldimode = sockmode(Curproc->input,SOCK_BINARY);
oldomode = sockmode(Curproc->output,SOCK_BINARY);
while((c = rrecvchar(Curproc->input)) == IAC){
c = rrecvchar(Curproc->input);
if(c > 250 && c < 255)
rrecvchar(Curproc->input);
}
sockmode(Curproc->output,oldomode);
sockmode(Curproc->input,oldimode);
/* Get rid of the prompt */
for(i=strlen(prompt);i != 0;i--)
tputc('\b');
for(i=strlen(prompt);i != 0;i--)
tputc(' ');
for(i=strlen(prompt);i != 0;i--)
tputc('\b');
tprintf("%c%c%c%c%c%c",IAC,WONT,TN_ECHO,IAC,WONT,TN_SUPPRESS_GA);
usflush(Curproc->output);
return c;
}
/* Print prompt and read reply,
* AX.25 and NETROM version - WG7J
* 'N' or 'n' returns -1, everything else return 0.
*/
int
mykeywait(prompt,m)
char *prompt;
struct mbx *m;
{
tputs(prompt);
usflush(Curproc->output);
if(recvline(m->user, m->line, MBXLINE) == -1)
return -1;
/* Only 'N' or 'n' really matters */
if(strchr(m->line,'N') || strchr(m->line,'n'))
return -1;
return 0;
}
#ifdef notdef
/* Echo some stuff for debugging */
void eout(char *s) {
puts(s);
fflush(stdout);
while(!kbhit());
getch();
}
#endif
/* Delete mail.lck files. This currently does NOT recurse - WG7J */
void RemoveMailLocks() {
int done;
struct ffblk ff;
char *buf;
buf = mallocw(BUFSIZ);
sprintf(buf,"%s/*.lck",Mailspool);
done = findfirst(buf,&ff,0);
while(!done) {
sprintf(buf,"%s/%s",Mailspool,ff.ff_name);
unlink(buf);
done=findnext(&ff);
}
free(buf);
}